/*
Copyright (C) 1997-2001 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// snd_loc.h -- private sound functions

// !!! if this is changed, the asm code must change !!!
typedef struct
{
	int			left;
	int			right;
} portable_samplepair_t;

typedef struct
{
	int 		length;
	int 		loopstart;
	int 		speed;			// not needed, because converted on load?
	int 		width;
	int 		channels;
#ifdef USE_OPENAL
	unsigned			alBufferNum;
#endif
	byte		data[1];		// variable sized
} sfxcache_t;

typedef struct sfx_s
{
	char 		name[MAX_QPATH];
	int			registration_sequence;
	sfxcache_t	*cache;
	char 		*truename;

	struct sfx_s *hashNext;
} sfx_t;

// a playsound_t will be generated by each call to S_StartSound,
// when the mixer reaches playsound->begin, the playsound will
// be assigned to a channel
typedef struct playsound_s
{
	struct playsound_s	*prev, *next;
	sfx_t		*sfx;
	float		volume;
	float		attenuation;
	int			entnum;
	int			entchannel;
	qboolean	fixed_origin;	// use origin field instead of entnum's origin
	vec3_t		origin;
	unsigned	begin;			// begin on this sample
} playsound_t;

typedef struct
{
	int			channels;
	int			samples;				// mono samples in buffer
	int			submission_chunk;		// don't mix less than this #
	int			samplepos;				// in mono samples
	int			samplebits;
	int			speed;
	byte		*buffer;
} dma_t;

// !!! if this is changed, the asm code must change !!!
typedef struct
{
	sfx_t		*sfx;			// sfx number
	int			leftvol;		// 0-255 volume
	int			rightvol;		// 0-255 volume
	int			end;			// end time in global paintsamples
	int 		pos;			// sample position in sfx
	int			looping;		// where to loop, -1 = no looping OBSOLETE?
	int			entnum;			// to allow overriding a specific sound
	int			entchannel;		//
	vec3_t		origin;			// only use if fixed_origin is set
	vec_t		dist_mult;		// distance multiplier (attenuation/clipK)
	int			master_vol;		// 0-255 master volume
	qboolean	fixed_origin;	// use origin instead of fetching entnum's origin
	qboolean	autosound;		// from an entity->sound, cleared each frame
} channel_t;

#ifdef USE_OPENAL
typedef enum psndType_s {
	PSND_ENTITY,
	PSND_FIXED,
	PSND_LOCAL,
} psndType_t;

typedef struct openal_channel_s
{
	qboolean			alRawStream;
	qboolean			alRawPlaying;
	psndType_t			psType;
	sfx_t				*sfx;			// NULL if unused
	int					entNum;			// To allow overriding a specific sound
	int					entChannel;
	int					startTime;		// For overriding oldest sounds
	qboolean			alLooping;		// Looping sound
	int					alLoopEntNum;	// Looping entity number
	int					alLoopFrame;	// For stopping looping sounds
	vec3_t				origin;		// Only use if fixedPosition is set
	float				volume;
	float				distanceMult;
	unsigned			sourceNum;		// OpenAL source
} openal_channel_t;
#endif

/*
====================================================================

  SYSTEM SPECIFIC FUNCTIONS

====================================================================
*/

// initializes cycling through a DMA buffer and returns information on it
qboolean SNDDMA_Init(void);

// gets the current DMA position
int		SNDDMA_GetDMAPos(void);

// shutdown the DMA xfer.
void	SNDDMA_Shutdown(void);

void	SNDDMA_BeginPainting (void);

void	SNDDMA_Submit(void);

#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
// custom Snd_Memset implementation for glibc memset bug workaround
void Snd_Memset (void* dest, const int val, const size_t count);
#else
#define Snd_Memset memset
#endif

//====================================================================

#define	MAX_CHANNELS			32
extern	channel_t   channels[MAX_CHANNELS];

extern	int		paintedtime;
extern	int		s_rawend;
/*extern	vec3_t	listener_origin;
extern	vec3_t	listener_forward;
extern	vec3_t	listener_right;
extern	vec3_t	listener_up;*/
extern	dma_t	dma;
extern	playsound_t	s_pendingplays;

#define	MAX_RAW_SAMPLES	8192
extern	portable_samplepair_t	s_rawsamples[MAX_RAW_SAMPLES];

extern cvar_t	*s_volume;
extern cvar_t	*s_nosound;
extern cvar_t	*s_loadas8bit;
extern cvar_t	*s_khz;
extern cvar_t	*s_show;
extern cvar_t	*s_mixahead;
extern cvar_t	*s_testsound;
extern cvar_t	*s_primary;

extern cvar_t	*s_swapstereo;

void S_InitScaletable (void);

sfxcache_t *S_LoadSound (sfx_t *s);

void S_IssuePlaysound (playsound_t *ps);

void S_PaintChannels(int endtime);

// picks a channel based on priorities, empty slots, number of channels
//channel_t *S_PickChannel(int entnum, int entchannel);

// spatializes a channel
//void S_Spatialize(channel_t *ch);

#ifdef USE_OPENAL
extern qboolean alSound;
qboolean ALSnd_Init (void);
void ALSnd_Shutdown (void);
void ALSnd_CreateBuffer (sfxcache_t *sc, int width, int channels, byte *data, int size, int frequency);
void ALSnd_DeleteBuffer (sfxcache_t *sc);
void ALSnd_StopAllSounds (void);
void ALSnd_Update (const vec3_t position, const vec3_t velocity, const vec3_t at, const vec3_t up);
void ALSnd_Activate (qboolean active);
void ALSnd_SoundInfo(void);
#endif

